package jmine.tec.test.testcase;

import java.util.Collection;

import junit.framework.TestCase;
import junit.framework.TestSuite;

import org.apache.log4j.Logger;
import org.springframework.transaction.TransactionStatus;

import bancosys.tec.persist.bussobj.PersistableBusinessObject;
import bancosys.tec.persist.dao.BeanNotFoundException;
import bancosys.tec.persist.persister.DefaultPersister;
import bancosys.tec.persist.persister.PurePersister;

/**
 * @created Jun 14, 2006
 * @author Gustavo Almeida
 * @param <T> classe do bean a ser testado.
 */
public abstract class BOBaseTestCase<T extends PersistableBusinessObject> extends AbstractBOBaseTestCase<T> {
    private static final Logger LOG = Logger.getLogger(BOBaseTestCase.class);

    /**
     * Construtor.
     */
    public BOBaseTestCase() {
        super();
    }

    /**
     * Construtor.
     * 
     * @param name nome.
     */
    public BOBaseTestCase(String name) {
        super(name);
    }

    /**
     * Testa a operação "save".
     */
    public void testSave() {
        LOG.trace("testSave()");

        TransactionStatus status = this.getHelper().getTransactionStatus();
        T bo;
        try {
            bo = this.getNewBOInstance();
            this.fillData(0, bo);
            this.preencheIdNosTestes(bo);
            this.saveBO(bo);
        } finally {
            this.getHelper().commit(status);
        }

        status = this.getHelper().getTransactionStatus();
        try {
            Collection<T> collection = this.findAllData();
            assertEquals(1, collection.size());
            bo = collection.iterator().next();
            this.compareData(0, bo);
            this.comparaIdNosTestes(bo);
        } catch (BeanNotFoundException e) {
            throw new TestCaseException(e);
        } finally {
            this.getHelper().commit(status);
        }
    }

    /**
     * Testa a operação update.
     */
    public void testUpdate() {
        LOG.trace("testUpdate()");

        TransactionStatus status = this.getHelper().getTransactionStatus();
        Collection<T> collection;
        T bo;
        try {
            collection = this.findAllData();
            assertTrue(collection.size() == 1);
            bo = collection.iterator().next();

            this.fillData(1, bo);
            this.preencheIdNosTestes(bo);
            this.saveBO(bo);
        } finally {
            this.getHelper().commit(status);
        }

        status = this.getHelper().getTransactionStatus();
        try {
            collection = this.findAllData();
            assertEquals(1, collection.size());

            bo = collection.iterator().next();
            this.compareData(1, bo);
            this.comparaIdNosTestes(bo);
        } catch (BeanNotFoundException e) {
            throw new TestCaseException(e);
        } finally {
            this.getHelper().commit(status);
        }
    }

    /**
     * Test a operação remove.
     */
    public void testRemove() {
        LOG.trace("testRemove()");

        TransactionStatus status = this.getHelper().getTransactionStatus();
        Collection<T> collection;
        try {
            collection = this.findAllData();
            assertEquals("deveria existir apenas 1 instância para remover", 1, collection.size());

            T bo = collection.iterator().next();
            this.removeBO(bo);
        } finally {
            this.getHelper().commit(status);
        }

        status = this.getHelper().getTransactionStatus();
        try {
            collection = this.findAllData();
            assertEquals(0, collection.size());
        } finally {
            this.getHelper().commit(status);
        }
    }

    /**
     * Método utilizado para salvar o BO criado pelo getSavedTestData(). Pode ser sobrecarregado com a intenção de executar alguma
     * verificação antes de salvar o BO.
     * 
     * @param bo O bo sendo salvo.
     */
    @Override
    protected void doSaveTestData(T bo) {
        PurePersister<T> adapter = new PurePersister<T>();
        adapter.setValidatorFactory(this.getValidatorFactory());
        adapter.setSessionFactory(this.getHelper().getSessionFactory());
        adapter.setAuditManager(this.getHelper().getAuditManager());
        adapter.setTarget(bo);
        adapter.save();
    }

    /**
     * Salva o bean.
     * 
     * @param bo bean.
     */
    protected void saveBO(T bo) {
        DefaultPersister<T> adapter = this.getPersister(bo);
        adapter.save();
    }

    /**
     * Remove o bean
     * 
     * @param bo bean.
     */
    protected void removeBO(T bo) {
        DefaultPersister<T> adapter = this.getPersister(bo);
        adapter.remove();
    }

    /**
     * Devolve um DefaultPersister configurado para o teste.
     * 
     * @param bo bean
     * @return um default persister
     */
    protected DefaultPersister<T> getPersister(T bo) {
        DefaultPersister<T> adapter = new DefaultPersister<T>();
        adapter.setValidatorFactory(this.getValidatorFactory());
        adapter.setSessionFactory(this.getHelper().getSessionFactory());
        adapter.setAuditManager(this.getHelper().getAuditManager());
        adapter.setTarget(bo);
        return adapter;
    }

    /**
     * Devolve a suite padrão de testes.
     * 
     * @param clazz classe do testcase
     * @return a suite de testes.
     * @throws TestCaseException
     */
    public static TestSuite getDefaultSuite(Class<? extends TestCase> clazz) {
        return getSuite(clazz, "testSave", "testUpdate", "testRemove", "testGetTestData", "testDAOQuerySyntax");
    }

}
